
import Taro from "@tarojs/taro";
import { Point, TRadian } from "fabric";
import utils from "src/utils/utils";

const LEFT = 'left';
const TOP = 'top';
const MOVING = 'moving';

const fabricUtils = {


    touchEvents: ['touchstart', 'touchmove', 'touchend'],

    isTouchEvent(event) {
        return this.touchEvents.includes(event.type) ||
            (event).pointerType === 'touch';

    },

    getTouchInfo(event) {
        const touchProp = (event).changedTouches;
        if (touchProp && touchProp[0]) {
            return touchProp[0];
        }
        return event;
    },

    getPointer(event) {
        const _evt = this.getTouchInfo(event);
        return new Point(_evt.x, _evt.y);
    },

    degreesToRadians(degrees) { return degrees * Math.PI / 180 },
    radiansToDegrees(radians) { return radians / Math.PI / 180 },

    // 创建canvas
    creatCanvas(width = 1024, height = 1024) {
        if (utils.isH5) {
            const canvas = new OffscreenCanvas(width, height);
            return canvas;
        } else {
            const canvas = Taro.createOffscreenCanvas({ type: '2d', width, height });
            return canvas;
        }
    },

    isActiveSelection(fabricObject) {
        return !!fabricObject && 'multiSelectionStacking' in fabricObject;
    },

    isCollection(fabricObject) {
        return !!fabricObject && Array.isArray((fabricObject)._objects);
    },

    getActionFromCorner(
        alreadySelected,
        corner,
        e,
        target,
    ) {
        if (!corner || !alreadySelected) {
            return 'drag';
        }
        const control = target.controls[corner];
        return control.getActionName(e, control, target);
    },

    isLocked(target, lockingKey) {
        return target[lockingKey]
    },

    fireEvent(eventName, options,) {
        const {
            transform: { target },
        } = options;
        target.canvas?.dispatchEvent({
            ...options,
            target,
            type: `object:${eventName}`
        });
        target.fire(eventName, options);
    },

    commonEventInfo(eventData, transform, x, y) {
        return {
            e: eventData,
            transform,
            pointer: new Point(x, y),
        };
    },

    dragHandler(eventData, transform, x, y) {
        const { target, offsetX, offsetY } = transform,
            newLeft = x - offsetX,
            newTop = y - offsetY,
            moveX = !fabricUtils.isLocked(target, 'lockMovementX') && target.left !== newLeft,
            moveY = !fabricUtils.isLocked(target, 'lockMovementY') && target.top !== newTop;
        moveX && target.set(LEFT, newLeft);
        moveY && target.set(TOP, newTop);
        if (moveX || moveY) {
            fabricUtils.fireEvent(MOVING, fabricUtils.commonEventInfo(eventData, transform, x, y));
        }
        return moveX || moveY;
    },

    getEventPoints(canvas, e) {
        const viewportPoint = canvas.getViewportPoint(e);
        // const scenePoint = canvas.getScenePoint(e);
        return {
            viewportPoint,
            // scenePoint,
            pointer: viewportPoint,
            // absolutePointer: scenePoint,
        };
    },

    saveObjectTransform(target) {
        return {
            scaleX: target.scaleX,
            scaleY: target.scaleY,
            skewX: target.skewX,
            skewY: target.skewY,
            angle: target.angle,
            left: target.left,
            flipX: target.flipX,
            flipY: target.flipY,
            top: target.top,
        }
    },

    removeFromArray(array, value) {
        const idx = array.indexOf(value);
        if (idx !== -1) {
            array.splice(idx, 1);
        }
        return array;
    },

    syntheticEventConfig: {
        mouse: {
            in: 'over',
            out: 'out',
            targetIn: 'mouseover',
            targetOut: 'mouseout',
            canvasIn: 'mouse:over',
            canvasOut: 'mouse:out',
        },
        drag: {
            in: 'enter',
            out: 'leave',
            targetIn: 'dragenter',
            targetOut: 'dragleave',
            canvasIn: 'drag:enter',
            canvasOut: 'drag:leave',
        },
    },

    halfPI: Math.PI / 2,

    cos(angle: number): number {
        if (angle === 0) {
            return 1;
        }
        const angleSlice = Math.abs(angle) / this.halfPI;
        switch (angleSlice) {
            case 1:
            case 3:
                return 0;
            case 2:
                return -1;
        }
        return Math.cos(angle);
    },

    sin(angle: TRadian): number {
        if (angle === 0) {
            return 0;
        }
        const angleSlice = angle / this.halfPI;
        const value = Math.sign(angle);
        switch (angleSlice) {
            case 1:
                return value;
            case 2:
                return 0;
            case 3:
                return -value;
        }
        return Math.sin(angle);
    },

    /**
     * Returns true if context has transparent pixel
     * at specified location (taking tolerance into account)
     * @param {CanvasRenderingContext2D} ctx context
     * @param {Number} x x coordinate in canvasElementCoordinate, not fabric space. integer
     * @param {Number} y y coordinate in canvasElementCoordinate, not fabric space. integer
     * @param {Number} tolerance Tolerance pixels around the point, not alpha tolerance, integer
     * @return {boolean} true if transparent
     */
    isTransparent(
        ctx: CanvasRenderingContext2D,
        x: number,
        y: number,
        tolerance: number,
    ): boolean {
        tolerance = Math.round(tolerance);
        const size = tolerance * 2 + 1;
        const { data } = ctx.getImageData(x - tolerance, y - tolerance, size, size);

        // Split image data - for tolerance > 1, pixelDataSize = 4;
        for (let i = 3; i < data.length; i += 4) {
            const alphaChannel = data[i];
            if (alphaChannel > 0) {
                return false;
            }
        }
        return true;
    }

}

export default fabricUtils;